package com.cover.fti.play;

import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Random;

import org.anddev.andengine.audio.music.Music;
import org.anddev.andengine.audio.music.MusicFactory;
import org.anddev.andengine.audio.sound.Sound;
import org.anddev.andengine.audio.sound.SoundFactory;
import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.handler.IUpdateHandler;
import org.anddev.andengine.engine.handler.timer.ITimerCallback;
import org.anddev.andengine.engine.handler.timer.TimerHandler;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.modifier.MoveModifier;
import org.anddev.andengine.entity.modifier.MoveXModifier;
import org.anddev.andengine.entity.modifier.MoveYModifier;
import org.anddev.andengine.entity.primitive.Rectangle;
import org.anddev.andengine.entity.scene.CameraScene;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnAreaTouchListener;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.scene.Scene.ITouchArea;
import org.anddev.andengine.entity.shape.IShape;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.entity.sprite.AnimatedSprite.IAnimationListener;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.entity.text.ChangeableText;
import org.anddev.andengine.entity.text.Text;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.opengl.font.Font;
import org.anddev.andengine.opengl.font.FontFactory;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BuildableBitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.buildable.builder.BlackPawnTextureBuilder;
import org.anddev.andengine.opengl.texture.atlas.buildable.builder.ITextureBuilder.TextureAtlasSourcePackingException;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.ui.activity.BaseGameActivity;
import org.anddev.andengine.util.HorizontalAlign;

import com.cover.fti.BubbleDefenseActivity;
import com.cover.fti.Score;
import com.cover.fti.ScoreDatabase;
import com.cover.fti.play.Tower.TOWER;
import com.qwerjk.andengine.opengl.texture.region.PixelPerfectTextureRegionFactory;
import com.qwerjk.andengine.opengl.texture.region.PixelPerfectTiledTextureRegion;
import com.welovecoding.towerdefense.ProgressBar;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Handler;
import android.text.method.DateTimeKeyListener;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;

public class PlayGameActivity extends BaseGameActivity implements
		IOnSceneTouchListener, IOnAreaTouchListener, IAnimationListener {

	public static final int CAMERA_WIDTH = 720;
	public static final int CAMERA_HEIGHT = 480;

	public static final int WALL_TOWER = 100;
	public static final int MENU_TOWER = 75;
	public static final int STATUS_PLAYER = 75;
	private static final int[] TOWER_ID = { 1, 2, 3 };
	private static int TOWER_SIZE = 3;
	private static final int MAX_BOM = 10;
	private static int ENEMY_SIZE = 12;

	private int CURRENT_LEVEL = 1;
	Level level = new Level();

	private EngineOptions engineOptions;
	private Handler mHandler;
	private Camera mCamera;
	public static Scene mMainScene;
	private CameraScene mPauseScene, mGameOverScene, mLevelCompleteScene;
	private boolean pauseFlag = false;
	private boolean runningFlag = false;
	private Music mBackgroundMusic;
	private Sound mShootingSound, mBombSound, mBombExplodeSound,
			mLevelCompleteSound, mGameOverSound, mNextLevelSound;
	private long score = 0;
	public static long gold = 0;

	private ChangeableText mScoreTextValue, mLifeText, mLevelText;
	public static ChangeableText mGoldTextValue;
	private Text mGoldText, mScoreText;
	private ProgressBar mLifeHUD;
	private int WALL_LIFE = 100;
	private BitmapTextureAtlas mFontTexture;
	private Font mFont;

	BitmapTextureAtlas mBackgroundAtlas;
	TextureRegion mBackgroundTextureRegion;
	BuildableBitmapTextureAtlas mSceneAtlas;
	TextureRegion mPauseTextureRegion;
	TextureRegion mGameOverTextureRegion;
	TextureRegion mLevelCompleteTextureRegion;

	BitmapTextureAtlas[] mEnemyAtlas;
	PixelPerfectTiledTextureRegion[] mEnemyPerfectTiledTextureRegion;
	Enemy[] mEnemy;
	LinkedList<Enemy> mEnemyLL;
	LinkedList<Enemy> mEnemyToBeAdded;
	EnemiesPool[] mEnemiesPool;

	BitmapTextureAtlas mBombAtlas;
	PixelPerfectTiledTextureRegion mBombPerfectTiledTextureRegion;
	Bomb mBomb;
	LinkedList<Bomb> mBombLL;
	LinkedList<Bomb> mBombToBeAdded;
	BombsPool mBombsPool;

	BuildableBitmapTextureAtlas mTowerTextureAtlas;
	TiledTextureRegion mTowerTextureRegion;
	TiledTextureRegion mTower2TextureRegion;
	TiledTextureRegion mTower3TextureRegion;
	Tower[] mTower;
	LinkedList<Tower> mTowerLL;
	LinkedList<Tower> mTowerToBeAdded;
	TowersPool[] mTowersPool;
	Rectangle backTower;

	BitmapTextureAtlas mBulletAtlas;
	PixelPerfectTiledTextureRegion mBullPerfectTiledTextureRegion;
	PixelPerfectTiledTextureRegion mBull2PerfectTiledTextureRegion;
	PixelPerfectTiledTextureRegion mBull3PerfectTiledTextureRegion;
	Bullet[] mBullet;
	LinkedList<Bullet> mBulletLL;
	LinkedList<Bullet> mBulletToBeAdded;
	BulletsPool[] mBulletsPool;

	TextureRegion mLifeBackgroundRegion;
	TextureRegion mStatusBackgroundRegion;
	
	@Override
	public Engine onLoadEngine() {
		this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);

		engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE,
				new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT),
				this.mCamera).setNeedsMusic(true).setNeedsSound(true);
		return new Engine(engineOptions);
	}

	@Override
	public void onLoadResources() {
		mHandler = new Handler();

		// load font
		this.mFontTexture = new BitmapTextureAtlas(256, 256,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		this.mFont = FontFactory.create(mFontTexture, Typeface.DEFAULT_BOLD,
				24, true, Color.BLACK);
		this.mEngine.getTextureManager().loadTexture(mFontTexture);
		this.mEngine.getFontManager().loadFont(mFont);

		BitmapTextureAtlasTextureRegionFactory
				.setAssetBasePath("gfx/gameplay/");

		// load background
		this.mBackgroundAtlas = new BitmapTextureAtlas(1024, 1024,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		this.mBackgroundTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createFromAsset(mBackgroundAtlas, this, "maps1.png", 0, 0);
		this.mEngine.getTextureManager().loadTexture(mBackgroundAtlas);

		mSceneAtlas = new BuildableBitmapTextureAtlas(512, 512,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		mPauseTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createFromAsset(mSceneAtlas, this, "pauseGame.png");
		mGameOverTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createFromAsset(mSceneAtlas, this, "gameOver.png");
		mLevelCompleteTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createFromAsset(mSceneAtlas, this, "levelComplete.png");
		mLifeBackgroundRegion = BitmapTextureAtlasTextureRegionFactory
				.createFromAsset(mSceneAtlas, this, "hudbar.png");
		mStatusBackgroundRegion = BitmapTextureAtlasTextureRegionFactory
				.createFromAsset(mSceneAtlas, this, "statusbar.png");

		try {
			mSceneAtlas.build(new BlackPawnTextureBuilder(2));
		} catch (TextureAtlasSourcePackingException e1) {
			e1.printStackTrace();
		}
		this.mEngine.getTextureManager().loadTexture(mSceneAtlas);

		PixelPerfectTextureRegionFactory.setAssetBasePath("gfx/gameplay/");

		// load enemy
		this.mEnemyAtlas = new BitmapTextureAtlas[ENEMY_SIZE];
		for (int i = 0; i < mEnemyAtlas.length; i++) {
			this.mEnemyAtlas[i] = new BitmapTextureAtlas(512, 512,
					TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		}

		this.mEnemyPerfectTiledTextureRegion = new PixelPerfectTiledTextureRegion[12];
		this.mEnemyPerfectTiledTextureRegion[0] = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(mEnemyAtlas[0], this, "enemy1.png", 0, 0,
						4, 2);
		this.mEnemyPerfectTiledTextureRegion[1] = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(mEnemyAtlas[1], this, "enemy5.png", 0, 0,
						4, 2);
		this.mEnemyPerfectTiledTextureRegion[2] = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(mEnemyAtlas[2], this, "enemy6.png", 0, 0,
						4, 2);
		this.mEnemyPerfectTiledTextureRegion[3] = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(mEnemyAtlas[3], this, "boss1.png", 0, 0,
						4, 2);
		this.mEnemyPerfectTiledTextureRegion[4] = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(mEnemyAtlas[4], this, "enemy1.png", 0, 0,
						4, 2);
		this.mEnemyPerfectTiledTextureRegion[5] = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(mEnemyAtlas[5], this, "enemy2.png", 0, 0,
						4, 2);
		this.mEnemyPerfectTiledTextureRegion[6] = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(mEnemyAtlas[6], this, "enemy3.png", 0, 0,
						4, 2);
		this.mEnemyPerfectTiledTextureRegion[7] = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(mEnemyAtlas[7], this, "boss1.png", 0, 0,
						4, 2);
		this.mEnemyPerfectTiledTextureRegion[8] = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(mEnemyAtlas[8], this, "enemy4.png", 0, 0,
						4, 2);
		this.mEnemyPerfectTiledTextureRegion[9] = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(mEnemyAtlas[9], this, "enemy5.png", 0, 0,
						4, 2);
		this.mEnemyPerfectTiledTextureRegion[10] = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(mEnemyAtlas[10], this, "enemy6.png", 0,
						0, 4, 2);
		this.mEnemyPerfectTiledTextureRegion[11] = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(mEnemyAtlas[11], this, "boss2.png", 0, 0,
						4, 2);

		this.mEnemy = new Enemy[ENEMY_SIZE];
		for (int i = 0; i < mEnemy.length; i++) {
			this.mEnemy[i] = new Enemy(0, 0,
					mEnemyPerfectTiledTextureRegion[i], mFont, i);
		}

		this.mEnemiesPool = new EnemiesPool[mEnemy.length];
		for (int i = 0; i < mEnemy.length; i++) {
			this.mEnemiesPool[i] = new EnemiesPool(mEnemy[i], i);
		}
		for (int i = 0; i < ENEMY_SIZE; i++) {
			this.mEngine.getTextureManager().loadTexture(mEnemyAtlas[i]);
		}

		// load bomb
		this.mBombAtlas = new BitmapTextureAtlas(128, 128,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		this.mBombPerfectTiledTextureRegion = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(mBombAtlas, this, "bomb.png", 0, 0, 4, 1);
		this.mBomb = new Bomb(0, 0, mBombPerfectTiledTextureRegion);
		this.mBombsPool = new BombsPool(mBomb);
		this.mEngine.getTextureManager().loadTexture(mBombAtlas);

		// load tower
		this.mTowerTextureAtlas = new BuildableBitmapTextureAtlas(256, 256,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);

		this.mTowerTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createTiledFromAsset(mTowerTextureAtlas, this, "tower1.png",
						1, 1);
		this.mTower2TextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createTiledFromAsset(mTowerTextureAtlas, this, "tower2.png",
						1, 1);
		this.mTower3TextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createTiledFromAsset(mTowerTextureAtlas, this, "tower3.png",
						1, 1);
		try {
			mTowerTextureAtlas.build(new BlackPawnTextureBuilder(3));
		} catch (TextureAtlasSourcePackingException e1) {
			e1.printStackTrace();
		}
		this.mEngine.getTextureManager().loadTexture(mTowerTextureAtlas);

		mTower = new Tower[TOWER_SIZE];
		this.mTower[0] = new Tower(0, 0, 60, 60, mTowerTextureRegion,
				TOWER.NORMAL);
		this.mTower[1] = new Tower(0, 0, 60, 60, mTower2TextureRegion,
				TOWER.HEAVY);
		this.mTower[2] = new Tower(0, 0, 60, 60, mTower3TextureRegion,
				TOWER.DESTRUCTION);

		this.mTowersPool = new TowersPool[mTower.length];
		for (int i = 0; i < mTower.length; i++) {
			mTowersPool[i] = new TowersPool(mTower[i], i);
		}

		// load bullet
		this.mBulletAtlas = new BitmapTextureAtlas(512, 512,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		this.mBullPerfectTiledTextureRegion = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(this.mBulletAtlas, this, "bullet_1.png",
						0, 0, 4, 2);
		this.mBull2PerfectTiledTextureRegion = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(mBulletAtlas, this, "bullet_2.png", 128,
						0, 4, 2);
		this.mBull3PerfectTiledTextureRegion = PixelPerfectTextureRegionFactory
				.createTiledFromAsset(mBulletAtlas, this, "bullet_3.png", 256,
						0, 4, 2);

		mBullet = new Bullet[mTower.length];
		this.mBullet[0] = new Bullet(0, 0, mBullPerfectTiledTextureRegion,
				mTower[0].getTipeTower());
		this.mBullet[1] = new Bullet(0, 0, mBull2PerfectTiledTextureRegion,
				mTower[1].getTipeTower());
		this.mBullet[2] = new Bullet(0, 0, mBull3PerfectTiledTextureRegion,
				mTower[2].getTipeTower());

		mBulletsPool = new BulletsPool[mBullet.length];
		for (int i = 0; i < mBullet.length; i++) {
			this.mBulletsPool[i] = new BulletsPool(mBullet[i], i);
		}
		this.mEngine.getTextureManager().loadTexture(mBulletAtlas);

		SoundFactory.setAssetBasePath("mfx/");

		// load sound
		try {
			mShootingSound = SoundFactory.createSoundFromAsset(
					mEngine.getSoundManager(), this, "shoot.mp3");
			mBombSound = SoundFactory.createSoundFromAsset(
					mEngine.getSoundManager(), this, "bomb.wav");
			mBombExplodeSound = SoundFactory.createSoundFromAsset(
					mEngine.getSoundManager(), this, "bubble_explode.wav");
			mLevelCompleteSound = SoundFactory.createSoundFromAsset(
					mEngine.getSoundManager(), this, "level_complete.wav");
			mGameOverSound = SoundFactory.createSoundFromAsset(
					mEngine.getSoundManager(), this, "game_over.wav");
			mNextLevelSound = SoundFactory.createSoundFromAsset(
					mEngine.getSoundManager(), this, "levelup.wav");
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		MusicFactory.setAssetBasePath("mfx/");

		// load music
		try {
			mBackgroundMusic = MusicFactory.createMusicFromAsset(
					mEngine.getMusicManager(), this, "background_mixed.mp3");
			mBackgroundMusic.setLooping(true);
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public Scene onLoadScene() {
		mEngine.registerUpdateHandler(new FPSLogger());
		mPauseScene = new CameraScene(mCamera);
		Sprite pauseSprite = new Sprite(
				(CAMERA_WIDTH - mPauseTextureRegion.getWidth()) / 2,
				(CAMERA_HEIGHT - mPauseTextureRegion.getHeight()) / 2,
				mPauseTextureRegion);
		mPauseScene.attachChild(pauseSprite);
		mPauseScene.setBackgroundEnabled(false);

		mGameOverScene = new CameraScene(mCamera);
		Sprite gameOverSprite = new Sprite(
				(CAMERA_WIDTH - mGameOverTextureRegion.getWidth()) / 2,
				(CAMERA_HEIGHT - mGameOverTextureRegion.getHeight()) / 2,
				mGameOverTextureRegion);
		mGameOverScene.attachChild(gameOverSprite);
		mPauseScene.setBackgroundEnabled(false);

		mLevelCompleteScene = new CameraScene(mCamera);
		Sprite levelCompleteSprite = new Sprite(
				(CAMERA_WIDTH - mLevelCompleteTextureRegion.getWidth()) / 2,
				(CAMERA_HEIGHT - mLevelCompleteTextureRegion.getHeight()) / 2,
				mLevelCompleteTextureRegion);
		mLevelCompleteScene.attachChild(levelCompleteSprite);
		mLevelCompleteScene.setBackgroundEnabled(false);

		PlayGameActivity.mMainScene = new Scene();
		createBackground();

		mBombLL = new LinkedList<Bomb>();
		mBombToBeAdded = new LinkedList<Bomb>();
		mEnemyLL = new LinkedList<Enemy>();
		mEnemyToBeAdded = new LinkedList<Enemy>();
		mTowerLL = new LinkedList<Tower>();
		mTowerToBeAdded = new LinkedList<Tower>();
		mBulletLL = new LinkedList<Bullet>();
		mBulletToBeAdded = new LinkedList<Bullet>();

		mScoreText = new Text(400, 5, this.mFont, "Score :",
				HorizontalAlign.LEFT);
		mScoreTextValue = new ChangeableText(400 + mScoreText.getWidth() + 5,
				5, this.mFont, score + "", HorizontalAlign.LEFT, 10);

		mGoldText = new Text(400, 5 + mScoreText.getHeight(), mFont, "Gold  :",
				HorizontalAlign.LEFT);
		mGoldTextValue = new ChangeableText(400 + mGoldText.getWidth() + 5,
				5 + mScoreText.getHeight(), mFont, gold + "",
				HorizontalAlign.LEFT, 10);

		mLifeText = new ChangeableText(300, 5, this.mFont, "Life:",
				"Life: XXX".length());
		mLifeText.setText("Life: 100");

		// mLifeHUD = new ProgressBar(this.mCamera, 10, 5, 250, 20);
		// mLifeHUD.setBackColor(1.0f, 0.0f, 0.0f, 1.0f);
		// mLifeHUD.setProgressColor(0.0f, 1.0f, 0.0f, 1.0f);
		// mLifeHUD.attachChild(mScoreText);
		// mLifeHUD.attachChild(mScoreTextValue);
		// mLifeHUD.attachChild(mLifeText);
		// mLifeHUD.attachChild(mGoldText);
		// mLifeHUD.attachChild(mGoldTextValue);

		Sprite lifeHUDBackground = new Sprite(0, 0, mLifeBackgroundRegion);
		Sprite statusBackground = new Sprite(280, 5, mStatusBackgroundRegion);

		mLifeHUD = new ProgressBar(this.mCamera, 52, 20, 165, 14);

		mLifeHUD.setFrameColor(0.0f, 0.0f, 0.0f, 0.0f);
		mLifeHUD.setBackColor(1.0f, 0.0f, 0.0f, 1.0f);
		mLifeHUD.setProgressColor(0.0f, 1.0f, 0.0f, 1.0f);
		mLifeHUD.attachChild(lifeHUDBackground);
		mLifeHUD.attachChild(statusBackground);
		mLifeHUD.attachChild(mScoreText);
		mLifeHUD.attachChild(mScoreTextValue);
		mLifeHUD.attachChild(mLifeText);
		mLifeHUD.attachChild(mGoldText);
		mLifeHUD.attachChild(mGoldTextValue);

		mLevelText = new ChangeableText(mLifeText.getInitialX(),
				mLifeText.getInitialY() + mLifeText.getHeight(), mFont,
				"LEVEL 1", "LEVEL X".length());
		mLevelText.setText("LEVEL 1");
		mLifeHUD.attachChild(mLevelText);
		mLevelText.setVisible(true);

		this.mCamera.setHUD(mLifeHUD);

		createEnemyTimeHandler();

		// create tower sprite
		int[][] dispTowerPosition = new int[][] {
				{ mTowerTextureRegion.getWidth(),
						CAMERA_HEIGHT - mTowerTextureRegion.getHeight() },
				{ mTower2TextureRegion.getWidth() * 2 + 10,
						CAMERA_HEIGHT - mTower2TextureRegion.getHeight() },
				{ mTower2TextureRegion.getWidth() * 3 + 10,
						CAMERA_HEIGHT - mTower3TextureRegion.getHeight() } };
		AnimatedSprite[] dispTower = new AnimatedSprite[mTower.length];

		for (int i = 0; i < dispTower.length; i++) {
			dispTower[i] = new AnimatedSprite(dispTowerPosition[i][0],
					dispTowerPosition[i][1], mTower[i].getTextureRegion());
			dispTower[i].setUserData(new Integer(TOWER_ID[i]));
			mMainScene.attachChild(dispTower[i]);
			mMainScene.registerTouchArea(dispTower[i]);
		}

		mMainScene.setTouchAreaBindingEnabled(true);
		mMainScene.setOnAreaTouchListener(this);
		mMainScene.setOnSceneTouchListener(this);

		mMainScene.registerUpdateHandler(detect);

		createTowerTimeHandler();

		mBackgroundMusic.play();
		return mMainScene;
	}

	private void createBackground() {
		Sprite backgroundSprite = new Sprite(0, 0, mBackgroundTextureRegion);
		mMainScene.attachChild(backgroundSprite);
	}

	IUpdateHandler detect = new IUpdateHandler() {

		@Override
		public void reset() {
		}

		@Override
		public void onUpdate(float pSecondsElapsed) {
			Iterator<Tower> towers = mTowerLL.iterator();
			Tower _tower;

			while (towers.hasNext()) {
				_tower = towers.next();
				for (int i = 0; i < mTowersPool.length; i++) {
					if (_tower.getIndex() == mTowersPool[i].getIndex()) {
						if (_tower.getRemove()) {
							mTowersPool[i].recyclePoolItem(_tower);
							towers.remove();
							break;
						}
					}
				}
			}

			Iterator<Enemy> enemies = mEnemyLL.iterator();
			Enemy _enemy;

			while (enemies.hasNext()) {
				_enemy = enemies.next();
				_enemy.setAttackSpeed(_enemy.getAttackSpeed() - 1);
				if (_enemy.getX() <= WALL_TOWER && _enemy.getAttackSpeed() <= 1) {
					decreaseWallLife();
					_enemy.setAttackSpeed(50);
				}
			}
			Iterator<Bomb> bombs = mBombLL.iterator();
			Bomb _bomb;

			while (bombs.hasNext()) {
				_bomb = bombs.next();
				if (_bomb.getY() == _bomb.getTargetY()) {
					mBombExplodeSound.play();
					mBombsPool.recyclePoolItem(_bomb);
					bombs.remove();
				}

				enemies = mEnemyLL.iterator();
				while (enemies.hasNext()) {
					_enemy = enemies.next();
					if (_bomb.collidesWith(_enemy)) {
						_enemy.setLife(_enemy.getLife() - _bomb.getDamage());
						if (_enemy.getLife() <= 0) {
							for (int i = 0; i < mEnemiesPool.length; i++) {
								if (_enemy.getIndex() == mEnemiesPool[i]
										.getIndex()) {
									mEnemiesPool[i].recyclePoolItem(_enemy);
									enemies.remove();
									addScore();
									addGold();
									break;
								}
							}
						}

						_bomb.setHitTarget(true);
						mBombsPool.recyclePoolItem(_bomb);
						bombs.remove();
						break;
					}
				}
			}

			boolean hit = false;
			enemies = mEnemyLL.iterator();
			while (enemies.hasNext()) {
				_enemy = enemies.next();

				Iterator<Bullet> bullets = mBulletLL.iterator();
				Bullet _bullet;

				while (bullets.hasNext()) {
					_bullet = bullets.next();

					if (_bullet.getX() == _bullet.getTargetX()
							&& _bullet.getY() == _bullet.getY()) {
						for (int i = 0; i < mBulletsPool.length; i++) {
							if (mBulletsPool[i].getIndex() == _bullet
									.getIndexTipe()) {
								_bullet.stopAnimation();
								_bullet.animate(new long[] { 100L, 100L, 100L,
										100L }, 4, 7, true);
								mBulletsPool[i].recyclePoolItem(_bullet);
								bullets.remove();
								break;
							}
						}
						continue;
					}

					if (_bullet.collidesWith(_enemy)) {
						for (int i = 0; i < mBulletsPool.length; i++) {
							if (mBulletsPool[i].getIndex() == _bullet
									.getIndexTipe()) {
								_bullet.stopAnimation();
								_bullet.animate(new long[] { 100L, 100L, 100L,
										100L }, 4, 7, true);
								break;
							}
						}
						hit = true;
						_enemy.setLife(_enemy.getLife() - _bullet.getDamage());
						break;
					}
				}

				if (hit) {
					if (_enemy.getLife() <= 0) {
						for (int i = 0; i < mEnemiesPool.length; i++) {
							if (_enemy.getIndex() == mEnemiesPool[i].getIndex()) {
								mEnemiesPool[i].recyclePoolItem(_enemy);
								enemies.remove();
								addScore();
								addGold();
								break;
							}
						}
					}
				}
			}

			mBombLL.addAll(mBombToBeAdded);
			mBombToBeAdded.clear();

			mEnemyLL.addAll(mEnemyToBeAdded);
			mEnemyToBeAdded.clear();

			mBulletLL.addAll(mBulletToBeAdded);
			mBulletToBeAdded.clear();

			mTowerLL.addAll(mTowerToBeAdded);
			mTowerToBeAdded.clear();

		}
	};

	private void shootEnemy() {
		if (!mEnemyLL.isEmpty()) {
			Enemy enemy = mEnemyLL.getFirst();
			for (Tower tower : mTowerLL) {
				if (tower.getReadyToFire()) {
					for (int i = 0; i < mBulletsPool.length; i++) {
						if (tower.getTipeTower() == mBullet[i].getTipeTower()) {
							mBullet[i] = mBulletsPool[i].obtainPoolItem();
							mBullet[i].setPosition(tower);
							MoveModifier moveMod = new MoveModifier(
									mBullet[i].getSpeed(), mBullet[i].getX(),
									enemy.getX(), mBullet[i].getY(),
									enemy.getY());

							mBullet[i].setTargetX(enemy.getX());
							mBullet[i].setTargetY(enemy.getY());
							mBullet[i].registerEntityModifier(moveMod
									.deepCopy());
							mBullet[i].animate(new long[] { 100L, 100L, 100L,
									100L }, 0, 3, true);
							mMainScene.attachChild(mBullet[i]);
							mBulletToBeAdded.add(mBullet[i]);
							mShootingSound.play();
							break;
						}
					}
				}
			}
		}
	}

	private void createTowerTimeHandler() {
		TimerHandler towerTimeHandler;
		float mTowerFireTimeDelay = 1f;
		towerTimeHandler = new TimerHandler(mTowerFireTimeDelay, true,
				new ITimerCallback() {

					@Override
					public void onTimePassed(TimerHandler pTimerHandler) {
						shootEnemy();
					}
				});
		getEngine().registerUpdateHandler(towerTimeHandler);
	}

	int enemyCount = 0;

	public void addEnemy(int index) {
		if (CURRENT_LEVEL >= 12) {
			gameOver("win");
		} else {
			if (enemyCount < level.getEnemyCount()) {
				Random rand = new Random();

				int x = CAMERA_WIDTH
						+ mEnemyPerfectTiledTextureRegion[index].getWidth() / 2;
				int minY = (mEnemyPerfectTiledTextureRegion[index].getHeight() / 2)
						+ STATUS_PLAYER;
				int maxY = (int) (CAMERA_HEIGHT
						- (mEnemyPerfectTiledTextureRegion[index].getHeight() / 2) - MENU_TOWER);
				int rangeY = maxY - minY;
				// Log.d("range", "range y : " + rangeY);
				int y = rand.nextInt(rangeY) + minY;

				mEnemy[index] = mEnemiesPool[index].obtainPoolItem();

				mEnemy[index].setLife(level.getEnemyLife());
				mEnemy[index].setAttackSpeed(level.getEnemyAttackSpeed());
				mEnemy[index].setSpeed(level.getEnemyMovementSpeed());

				mEnemy[index].setPosition(x, y);
				long[] frameDuration = new long[] { 100L, 100L, 100L, 100L };
				mEnemy[index].animate(frameDuration, 0, 3, true);

				mMainScene.attachChild(mEnemy[index]);
				MoveXModifier moveXMod = new MoveXModifier(
						mEnemy[index].getSpeed(), x, WALL_TOWER);
				mEnemy[index].registerEntityModifier(moveXMod.deepCopy());
				mEnemyToBeAdded.add(mEnemy[index]);
				enemyCount++;
			} else {
				mNextLevelSound.play();
				enemyCount = 0;
				this.CURRENT_LEVEL += 1;
				getEngine().clearUpdateHandlers();
				createEnemyTimeHandler();
				createTowerTimeHandler();
			}
		}
	}

	private void createEnemyTimeHandler() {
		TimerHandler enemyTimerHandler;
		level.setLevel(this.CURRENT_LEVEL);
		float mEffectEnemyDelay = level.getEnemyDelay();
		mLevelText.setText("LEVEL " + CURRENT_LEVEL);
		mLevelText.setVisible(true);
		enemyTimerHandler = new TimerHandler(mEffectEnemyDelay, true,
				new ITimerCallback() {

					@Override
					public void onTimePassed(TimerHandler pTimerHandler) {
						addEnemy(level.getCurrentLevel() - 1);
						pTimerHandler.reset();
					}
				});
		getEngine().registerUpdateHandler(enemyTimerHandler);
	}

	@Override
	public void onLoadComplete() {
	}

	@Override
	public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
		if (pSceneTouchEvent.isActionDown()) {
			float x = pSceneTouchEvent.getX();
			float y = pSceneTouchEvent.getY();
			if (x > WALL_TOWER && y < CAMERA_HEIGHT - MENU_TOWER
					&& y > STATUS_PLAYER) {
				if (mBombLL.size() < MAX_BOM) {
					createBomb(x, y);
				}
			}

			return true;
		}
		if (pSceneTouchEvent.isActionMove()) {
			return true;
		}

		return false;
	}

	private void createBomb(final float pX, final float pY) {
		mBomb = mBombsPool.obtainPoolItem();
		mBomb.setPosition(pX, 0 - mBombPerfectTiledTextureRegion.getHeight());
		mBomb.setTargetY(pY);
		mMainScene.attachChild(mBomb);
		float moveDuration = mBomb.getSpeed();
		MoveYModifier moveYMod = new MoveYModifier(moveDuration, mBomb.getY(),
				pY);

		mBomb.registerEntityModifier(moveYMod.deepCopy());
		mBombToBeAdded.add(mBomb);
		mBombSound.play();
	}

	private void createNewTower(TouchEvent pSceneTouchEvent, int pTowerID,
			float x, float y) {
		final int tower_id = pTowerID - 1;
		TOWER tower = null;
		switch (tower_id) {
		case 0:
			tower = TOWER.NORMAL;
			break;
		case 1:
			tower = TOWER.HEAVY;
			break;
		case 2:
			tower = TOWER.DESTRUCTION;
			break;
		default:
			break;
		}
		if (gold > mTower[tower_id].getPrice()) {
			mTower[tower_id] = new Tower(x - (mTower[tower_id].getWidth() / 2),
					y - (mTower[tower_id].getHeight() / 2), 60, 60,
					mTower[tower_id].getTextureRegion(), tower) {

				public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
						float pTouchAreaLocalX, float pTouchAreaLocalY) {
					boolean canCreateTowerHere = false;
					boolean isCollideWithOtherTower = false;
					boolean isOverArea = false;
					if (this.getMove()) {
						setPosition(pSceneTouchEvent.getX()
								- (this.getWidth() / 2),
								pSceneTouchEvent.getY()
										- (this.getHeight() / 2));
						if (mTowerLL.size() > 1) {
							for (int i = 0; i < mTowerLL.size() - 1; i++) {
								Tower tower = mTowerLL.get(i);
								if (this.collidesWith(tower)) {
									isCollideWithOtherTower = true;
									break;
								} else {
									isCollideWithOtherTower = false;
								}
							}
						} else {
							isCollideWithOtherTower = false;
						}

						if (this.getX() < PlayGameActivity.WALL_TOWER
								- this.getWidth() / 2
								&& this.getY() < PlayGameActivity.CAMERA_HEIGHT
										- PlayGameActivity.MENU_TOWER
										- this.getHeight() / 2
								&& this.getY() > PlayGameActivity.STATUS_PLAYER
										+ this.getHeight() / 2) {
							isOverArea = false;
						} else {
							isOverArea = true;
						}

						if (!isCollideWithOtherTower && !isOverArea) {
							setBackColor(0f, 1f, 0f, 0.5f);
							canCreateTowerHere = true;
						} else {
							setBackColor(1f, 0, 0, 0.5f);
						}

					}
					if (pSceneTouchEvent.isActionUp()) {
						if (canCreateTowerHere) {
							this.setMove(false);
							this.setReadyToFire(true);
							this.setRemove(false);
							mMainScene.unregisterTouchArea(this);
							setBackColor(1, 1, 1, 0);
							minusGold(mTower[tower_id].getPrice());
						} else {
							this.setRemove(true);
						}
					}
					return true;
				}
			};
			mTowerToBeAdded.add(mTower[tower_id]);
			mMainScene.registerTouchArea(mTower[tower_id]);
			mMainScene.attachChild(mTower[tower_id]);
		}
	}

	@Override
	public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
			ITouchArea pTouchArea, float pTouchAreaLocalX,
			float pTouchAreaLocalY) {
		int ID = 0;
		try {
			ID = (Integer) ((IShape) pTouchArea).getUserData();
		} catch (ClassCastException cce) {
		}
		switch (pSceneTouchEvent.getAction()) {
		case TouchEvent.ACTION_DOWN:
			switch (ID) {
			case 1: {
				createNewTower(pSceneTouchEvent, ID, pSceneTouchEvent.getX(),
						pSceneTouchEvent.getY());

				return false;
			}
			case 2:
				createNewTower(pSceneTouchEvent, ID, pSceneTouchEvent.getX(),
						pSceneTouchEvent.getY());

				return false;
			case 3:
				createNewTower(pSceneTouchEvent, ID, pSceneTouchEvent.getX(),
						pSceneTouchEvent.getY());

				return false;
			default:
				return false;
			}
		}
		return false;
	}

	private void addScore() {
		this.score += 100;
		mScoreTextValue.setText(String.valueOf(score));
	}

	private void addGold() {
		gold += 100;
		mGoldTextValue.setText(String.valueOf(gold));
	}

	public static void minusGold(long value) {
		gold -= value;
		mGoldTextValue.setText(String.valueOf(gold));
	}

	private void decreaseWallLife() {
		this.WALL_LIFE -= 1;
		mLifeText.setText("Life: " + WALL_LIFE);
		mLifeHUD.setProgress(WALL_LIFE);
		if (WALL_LIFE <= 0) {
			gameOver("lose");
		}
	}

	private void gameOver(String pResult) {
		if (pResult.equalsIgnoreCase("win")) {
			mGameOverSound.play();
			mMainScene.setChildScene(mLevelCompleteScene, false, true, true);
		} else if (pResult.equalsIgnoreCase("lose")) {
			mLevelCompleteSound.play();
			mMainScene.setChildScene(mGameOverScene, false, true, true);
		}
		score += (WALL_LIFE * 100);
		score += gold;
		saveScore(score);
		gold = 0;
		score = 0;
		//mGoldTextValue.setText(gold + "");
		//mScoreTextValue.setText(score + "");
		mEngine.stop();

		mHandler.postDelayed(newGame, 3000);
	}

	private Runnable newGame = new Runnable() {
		public void run() {
			Intent intent = new Intent(PlayGameActivity.this,
					BubbleDefenseActivity.class);
			PlayGameActivity.this.startActivity(intent);
			finish();
		}
	};

	public boolean onKeyDown(final int pKeyCode, KeyEvent pEvent) {
		if (pKeyCode == KeyEvent.KEYCODE_MENU
				&& pEvent.getAction() == KeyEvent.ACTION_DOWN) {
			if (mEngine.isRunning() && mBackgroundMusic.isPlaying()) {
				pauseMusic();
				pauseFlag = true;
				pauseGame();
				Toast.makeText(this, "Menu Button to Resume",
						Toast.LENGTH_SHORT).show();
			} else {
				resumeMusic();
				pauseFlag = false;
				unPauseGame();
				mEngine.start();
			}
			return true;
		}
		return super.onKeyDown(pKeyCode, pEvent);
	}

	protected void onPause() {
		if (runningFlag) {
			pauseMusic();
			if (mEngine.isRunning()) {
				pauseGame();
				pauseFlag = true;
			}
		}
		super.onPause();
	}

	public void onResumeGame() {
		if (runningFlag) {
			if (pauseFlag) {
				pauseFlag = false;
				Toast.makeText(this, "Menu button to resume",
						Toast.LENGTH_SHORT).show();
			} else {
				resumeMusic();
				mEngine.stop();
			}
		} else {
			runningFlag = true;
		}
	}

	private void pauseMusic() {
		// pause music
		if (runningFlag) {
			if (!mBackgroundMusic.isPlaying()) {
				mBackgroundMusic.pause();
			}
		}
	}

	private void resumeMusic() {
		if (runningFlag) {
			if (!mBackgroundMusic.isPlaying()) {
				mBackgroundMusic.resume();
			}
		}
	}

	private void pauseGame() {
		if (runningFlag) {
			mMainScene.setChildScene(mPauseScene, false, true, true);
			mEngine.stop();
		}
	}

	private void unPauseGame() {
		mMainScene.clearChildScene();
	}

	@Override
	public void onAnimationEnd(AnimatedSprite pAnimatedSprite) {
		// TODO Auto-generated method stub

	}

	public void saveScore(long score) {
		ScoreDatabase scdb = new ScoreDatabase(getBaseContext());
		Score sc = scdb.getHighScore(getApplicationContext());
		Date d = new Date();
		String tgl = d.toLocaleString();
		if(sc.getTanggal() == null){
			sc = new Score();
			sc.setTanggal(tgl);
			sc.setHighScores(score);
			scdb.insertNewScore(getApplicationContext(), sc);
			Log.d("Database", "Success Insert");
			Log.d("Database", "Tanggal : "+sc.getTanggal());
			Log.d("Database", "Score : "+sc.getHighScores());
		} else {
			if(sc.getHighScores() < score){
				Score scNew = new Score();
				scNew.setTanggal(tgl);
				scNew.setHighScores(score);
				scdb.updateScore(getApplicationContext(), sc.getTanggal(), scNew.getTanggal(), scNew.getHighScores());
				Log.d("Database", "Success Update");
				Log.d("Database", "Tanggal : "+sc.getTanggal());
				Log.d("Database", "Score : "+sc.getHighScores());
			}
		}
	}
}
